package com.authine.cloudpivot.ext.service.invoice.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapBuilder;
import com.alibaba.cola.dto.SingleResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.authine.cloudpivot.ext.Enum.InvoiceBusinessType;
import com.authine.cloudpivot.ext.Enum.InvoiceStatus;
import com.authine.cloudpivot.ext.constants.ModelConst;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceApply;
import com.authine.cloudpivot.ext.dto.model.invoice.InvoiceDetail;
import com.authine.cloudpivot.ext.dto.query.InvoiceDetailQuery;
import com.authine.cloudpivot.ext.service.invoice.InvoiceDetailService;
import com.authine.cloudpivot.ext.utils.*;
import com.authine.mvp.app.launcher.dto.bo.response.BO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class InvoiceDetailServiceImpl implements InvoiceDetailService {

    public List<InvoiceDetail> listInvoiceDetail(InvoiceDetailQuery invoiceDetailQuery){
        StringBuffer sql = new StringBuffer("select detail.* from ");
        sql.append(JdbcTemplateUtils.getTableName(ModelConst.T_INVOICE_DETAIL)).append(" as detail");

        StringBuffer leftJoin = new StringBuffer();

        MapBuilder param = MapBuilder.create(new HashMap<>());
        StringBuffer whereSql = new StringBuffer(" where detail.deleted = 0");

        if(!CollectionUtils.isEmpty(invoiceDetailQuery.getBusinessTypes())||!CollectionUtils.isEmpty(invoiceDetailQuery.getInvoiceStatuses())){
            if(leftJoin.length()<=0){
                leftJoin.append(" left join ")
                        .append(JdbcTemplateUtils.getTableName(ModelConst.T_INVOICE_APPLY)).append(" as apply on detail.invoice_apply_id = apply.id");
            }
            if(!CollectionUtils.isEmpty(invoiceDetailQuery.getBusinessTypes())) {
                whereSql.append(" and apply.business_type in (:businessTypes)");
                param.put("businessTypes", invoiceDetailQuery.getBusinessTypes());
            }
            if(!CollectionUtils.isEmpty(invoiceDetailQuery.getInvoiceStatuses())) {
                whereSql.append(" and apply.statuss in (:statuses)");
                param.put("statuses", invoiceDetailQuery.getInvoiceStatuses());
            }
        }

        if(!CollectionUtils.isEmpty(invoiceDetailQuery.getIds())){
            whereSql.append(" and detail.id in (:ids)");
            param.put("ids", invoiceDetailQuery.getIds());
        }
        if(!CollectionUtils.isEmpty(invoiceDetailQuery.getInvoiceApplyIds())){
            whereSql.append(" and detail.invoice_apply_id in (:invoiceApplyId)");
            param.put("invoiceApplyId", invoiceDetailQuery.getInvoiceApplyIds());
        }
        if(!CollectionUtils.isEmpty(invoiceDetailQuery.getOffsetIds())){
            whereSql.append(" and detail.offset_id in (:offset_id)");
            param.put("offset_id", invoiceDetailQuery.getOffsetIds());
        }
        if(invoiceDetailQuery.getCanOffsetQuantity()!=null && invoiceDetailQuery.getCanOffsetQuantity()){
            whereSql.append(" and detail.offset_quantity <> detail.quantity");
        }
        if(invoiceDetailQuery.getCanOffsetTotal() != null && invoiceDetailQuery.getCanOffsetTotal()){
            whereSql.append(" and detail.offset_total <> detail.total");
        }
        String querySql = sql.append(leftJoin).append(whereSql).toString();
        log.info("querySql = {}, parameters = {}", querySql, JSONObject.toJSONString(param.build()));
        List<InvoiceDetail> detailList = JdbcTemplateUtils.queryForPOJOList(querySql, param.build(), ModelConst.T_INVOICE_DETAIL, InvoiceDetail.class);
        return detailList;

    }

    @Override
    public void deleteInvoiceDetail(Collection<String> invoiceDetailIds, Collection<String> invoiceIds){
        StringBuffer sql = new StringBuffer("select detail.* from ")
                .append(JdbcTemplateUtils.getTableName(ModelConst.T_INVOICE_DETAIL)).append(" as detail")
                .append(" left join ").append(JdbcTemplateUtils.getTableName(ModelConst.T_INVOICE_APPLY)).append(" as apply")
                .append(" on detail.invoice_apply_id = apply.id");
        MapBuilder<String, Object> mapBuilder = MapBuilder.create(new HashMap<>());
        sql.append(" where 1=1");
        if (!CollectionUtils.isEmpty(invoiceDetailIds)) {
            sql.append(" and detail.id in (:invoiceDetailIds)");
            mapBuilder.put("invoiceDetailIds", invoiceDetailIds);
        }
        if (!CollectionUtils.isEmpty(invoiceIds)) {
            sql.append(" and detail.invoice_apply_id in (:invoiceIds)");
            mapBuilder.put("invoiceIds", invoiceIds);
        }
        sql.append(" and apply.statuss in (:statuss)");
        mapBuilder.put("statuss", Arrays.asList(InvoiceStatus.New.name(), InvoiceStatus.Returned.name()));
        List<Map<String, Object>> detailListMap = jdbcTemplate.queryForList(sql.toString(), mapBuilder.build());
        BoResultFormat.resultFormat(detailListMap, ModelConst.T_INVOICE_DETAIL, false);
        List<InvoiceDetail> detailList = JSON.parseArray(JSON.toJSONString(detailListMap), InvoiceDetail.class);
        if (CollectionUtils.isEmpty(detailList)) {
            return;
        }
        List<String> writeBackTrade = new ArrayList<>();
        invoiceDetailIds = new ArrayList<>();
        for (InvoiceDetail invoiceDetail : detailList) {
            BoServiceUtils.deleteBo( ModelConst.T_INVOICE_DETAIL, invoiceDetail.getId(), true);
            invoiceDetailIds.add(invoiceDetail.getId());

            SingleResponse<BO> response = BoServiceUtils.loadBo(invoiceDetail.getInvoice_apply_id(), ModelConst.T_INVOICE_APPLY);
            InvoiceApply invoiceApply = BeanUtil.mapToBean(response.getData().getData(), InvoiceApply.class, true);

            if (InvoiceBusinessType.Product.name().equals(invoiceApply.getBusiness_type())
                    || InvoiceBusinessType.RedProduct.name().equals(invoiceApply.getBusiness_type())) {
                writeBackTrade.add(invoiceDetail.getTrade_id());
            }
        }
        invoiceDetailBillService.remove(invoiceDetailIds);

        Set<String> invoiceApplyIds = detailList.stream().map(InvoiceDetail::getInvoice_apply_id).collect(Collectors.toSet());
        for (String invoiceApplyId : invoiceApplyIds) {
            InvoiceApply invoiceApplyEntity = JdbcTemplateUtils.builder(ModelConst.T_INVOICE_APPLY).selectField("*")
                    .eq("id", invoiceApplyId).queryForPOJO(InvoiceApply.class);
            //不删除结算单的时候，重新计算（修改发票明细的时候重新计算）
            if (null != invoiceApplyEntity) {
                //删除后，新的发票明细
                List<InvoiceDetail> invoiceDetailEntities = listInvoiceDetail(InvoiceDetailQuery.builder().invoiceApplyIds(Collections.singleton(invoiceApplyId)).build());
                Assert.isTrue(!CollectionUtils.isEmpty(invoiceDetailEntities), "发票明细不可为空");

                BigDecimal sumAmount = CalculatorUtils.sum(invoiceDetailEntities, BiFunctionConst.invoiceDetailAmountFun);
                BigDecimal sumTotal = CalculatorUtils.sum(invoiceDetailEntities, BiFunctionConst.invoiceDetailTotalFun);
                BigDecimal sumTax = CalculatorUtils.sum(invoiceDetailEntities, BiFunctionConst.invoiceDetailTaxFun);

                invoiceApplyEntity.setTotal(sumTotal).setPrice_amount(sumAmount).setTax_amount(sumTax);
                BoServiceUtils.updateMainBo( ModelConst.T_INVOICE_APPLY, BeanUtil.beanToMap(invoiceApplyEntity));
            }
        }
        tradeService.writeBackAllowedInvoiceQuantity(writeBackTrade);

    }

}
